﻿using Coldairarrow.Entity.Base;
using Coldairarrow.Entity.DTO;
using Coldairarrow.Entity.PB;
using Coldairarrow.Util;
using EFCore.Sharding;
using LinqKit;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Coldairarrow.Business.PB
{
    public partial class PB_ProductionOrderDetailBusiness : BaseBusiness<PB_ProductionOrderDetail>, IPB_ProductionOrderDetailBusiness, ITransientDependency
    {
        public PB_ProductionOrderDetailBusiness(IDbAccessor db)
            : base(db)
        {
        }

        #region 外部接口

        public async Task<PageResult<PB_ProductionOrderDetail>> GetDataListAsync(PageInput<ConditionDTO> input)
        {
            var q = GetIQueryable();
            var where = LinqHelper.True<PB_ProductionOrderDetail>();
            var search = input.Search;

            //筛选
            if (!search.Condition.IsNullOrEmpty() && !search.Keyword.IsNullOrEmpty())
            {
                var newWhere = DynamicExpressionParser.ParseLambda<PB_ProductionOrderDetail, bool>(
                    ParsingConfig.Default, false, $@"{search.Condition}.Contains(@0)", search.Keyword);
                where = where.And(newWhere);
            }

            return await q.Where(where).GetPageResultAsync(input);
        }

        /// <summary>
        /// 联合查询生产订单信息,所有ID获取对应名称
        /// </summary>
        /// <param name="input">条件信息</param>
        /// <returns></returns>
        public async Task<PageResult<PB_ProductionOrderDetailListDTO>> GetDataListShowAllNameAsync(PB_ProductionOrderDetailInput input)
        {
            Expression<Func<PB_ProductionOrderDetail, PB_ProductionOrder, PB_Material, PB_ProcecureMain, PB_Workshop, PB_Station, PB_ProductionOrderDetailListDTO>> select = (a, b, c, d, e, f) => new PB_ProductionOrderDetailListDTO
            {
                POName = b.POName,//生产订单名称
                MaterialName = c.Name,//物料名称
                ProcecureName = d.Name,//工序名称
                WorkshopName = e.Name,//车间名称
                StationName = f.Name,//工位名称
                MaterialCode=c.Code,//物料编号
            };
            var search = input.Search;
            select = select.BuildExtendSelectExpre();
            var q_DesignDetail = GetIQueryable().Where(w => w.ParentId == input.ParentId);
            var q = from a in q_DesignDetail.AsExpandable()
                    join b in Db.GetIQueryable<PB_ProductionOrder>() on a.ParentId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()

                    join c in Db.GetIQueryable<PB_Material>() on a.MaterialId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()

                    join d in Db.GetIQueryable<PB_ProcecureMain>() on a.ProcecureId equals d.Id into ad
                    from d in ad.DefaultIfEmpty()

                    join e in Db.GetIQueryable<PB_Workshop>() on a.WorkshopId equals e.Id into ae
                    from e in ae.DefaultIfEmpty()

                    join f in Db.GetIQueryable<PB_Station>() on a.StationId equals f.Id into af
                    from f in af.DefaultIfEmpty()

                    select @select.Invoke(a, b, c, d, e, f);

            //筛选
            if (!search.Condition.IsNullOrEmpty() && !search.Keyword.IsNullOrEmpty())
            {
                var keyword = $"%{search.Keyword}%";
                q = q.Where(x => EF.Functions.Like(search.Condition, keyword));
            }

            return await q.GetPageResultAsync(input);

        }

        public async Task<PB_ProductionOrderDetail> GetTheDataAsync(string id)
        {
            return await GetEntityAsync(id);
        }

        public async Task AddDataAsync(PB_ProductionOrderDetail data)
        {
            var abcObject = new
            {
                //标识
                Key = "ZY0003",
                //josn
                Value = new
                {
                    Id = data.Id,
                    ParentId = data.ParentId
                }
            };
            data.QrCode = abcObject.ToString();
            await InsertAsync(data);
        }

        public async Task AddDataAsyncs(List<PB_ProductionOrderDetail> data)
        {
            await InsertAsync(data);
        }

        public async Task UpdateDataAsync(PB_ProductionOrderDetail data)
        {
            var abcObject = new
            {
                //标识
                Key = "ZY0003",
                //josn
                Value = new
                {
                    Id = data.Id,
                    ParentId = data.ParentId
                }
            };
            data.QrCode = abcObject.ToString();
            await UpdateAsync(data);
        }

        public async Task DeleteDataAsync(List<string> ids)
        {
            await DeleteAsync(ids);
        }

        public async Task<PageResult<Entity.DTO.PB_ProductionOrderDetailDTO>> GetDataListAsyncs(PageInput<ConditionDTO> input, string ParentId)
        {
            var search = input.Search;
            Expression<Func<PB_ProductionOrderDetail, PB_Material, PB_MaterialType, Base_UnitGroup, PB_DesignList, Entity.DTO.PB_ProductionOrderDetailDTO>> select = (a, b, c, d, e) => new Entity.DTO.PB_ProductionOrderDetailDTO
            {

                MaterialID = b.Id,//物料编号
                MaterialName = b.Name,//物料名称
                MaterialTypeId = c.Name,//类型名称
                MaterialCode = b.Code,//物料编号
                PackingSpec = b.Spec, //物料规格
                Weight = b.Weight,//理论重量
                UnitGroupName = d.Name,//单位名称
                DesignName = e.Name,
            };
            select = select.BuildExtendSelectExpre();
            var q = from a in GetIQueryable().AsExpandable()
                    join b in Db.GetIQueryable<PB_Material>() on a.MaterialId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    join c in Db.GetIQueryable<PB_MaterialType>() on b.MaterialTypeId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<Base_UnitGroup>() on b.UnitGroupId equals d.Id into ad
                    from d in ad.DefaultIfEmpty()
                    join e in Db.GetIQueryable<PB_DesignList>() on a.ProcecureId equals e.Id into ae
                    from e in ae.DefaultIfEmpty()
                    select @select.Invoke(a, b, c, d, e);
            return await q.GetPageResultAsync(input);
        }

        public async Task<Entity.DTO.PB_ProductionOrderDetailData> GetTheDataOrderDetail(string OrderDetailQrCode)
        {
            //解析任务单明细二维码
            string[] usermodel = OrderDetailQrCode.Split(',');
            string Id = usermodel[2].ToString();
            string sqlMain = @" delete from PB_JobBookingQrCode where OrderDetailId='" + Id + "' and ParentId is null ";
            await ExecuteSqlAsync(sqlMain);
            DataTable dt = await Db.GetDataTableWithSqlAsync("select a.*,b.`Code` as MaterialCode,b.`Name` as MaterialName,b.SimpleName as MaterialSimpleName,c.`Name` as MaterialTypeName,b.Spec as MaterialSpec,b.Price as MaterialPrice,b.QrCode as MaterialQrCode,d.`Name` as UnitGroupName,(a.Productionquantity-(SELECT IFNULL(SUM(Nums),0) FROM PB_JobBooking where ParentId=a.Id))  as WorkReportNum,e.IsRefurbishment from PB_ProductionOrderDetail as a left join PB_Material as b on a.MaterialId=b.Id left join PB_MaterialType as c on b.MaterialTypeId=c.Id left join Base_UnitGroup as d on b.UnitGroupId=d.Id left join PB_ProductionOrder as e on a.ParentId=e.Id where a.Id='" + Id + "'");
            Entity.DTO.PB_ProductionOrderDetailData qdata = new Entity.DTO.PB_ProductionOrderDetailData();
            foreach (DataRow dr in dt.Rows)
            {
                qdata.Id = dr["Id"].ToString();
                qdata.ParentId = dr["ParentId"].ToString();
                qdata.MaterialId = dr["MaterialId"].ToString();
                qdata.ProcecureId = dr["ProcecureId"].ToString();
                qdata.Nums = Convert.ToDouble(dr["Nums"]);
                qdata.Remarks = dr["Remarks"].ToString();
                qdata.StartDate = Convert.ToDateTime(dr["StartDate"]);
                qdata.EndDate = Convert.ToDateTime(dr["EndDate"]);
                qdata.CreateTime = Convert.ToDateTime(dr["CreateTime"]);
                qdata.CreatorId = dr["CreatorId"].ToString();
                qdata.Deleted = Convert.ToBoolean(dr["Deleted"]);
                qdata.HasCheck = Convert.ToBoolean(dr["HasCheck"]);
                qdata.QrCode = dr["QrCode"].ToString();
                qdata.WorkshopId = dr["WorkshopId"].ToString();
                qdata.StationId = dr["StationId"].ToString();
                qdata.Finishedproduct = dr["Finishedproduct"].ToString();
                qdata.Ofmaterial = dr["Ofmaterial"].ToString();
                qdata.Holespacing = dr["Holespacing"].ToString();
                qdata.Productionquantity = Convert.ToInt32(dr["Productionquantity"]);
                qdata.CompleteNums = Convert.ToDouble(dr["CompleteNums"]);
                qdata.MaterialCode = dr["MaterialCode"].ToString();
                qdata.MaterialName = dr["MaterialName"].ToString();
                qdata.MaterialSimpleName = dr["MaterialSimpleName"].ToString();
                qdata.MaterialTypeName = dr["MaterialTypeName"].ToString();
                qdata.MaterialSpec = dr["MaterialSpec"].ToString();
                qdata.MaterialQrCode = dr["MaterialQrCode"].ToString();
                qdata.UnitGroupName = dr["UnitGroupName"].ToString();
                qdata.WorkReportNum = Convert.ToDouble(dr["WorkReportNum"]);
                qdata.IsRefurbishment = Convert.ToInt32(dr["IsRefurbishment"]);
            }
            return qdata;
        }

        public async Task<Entity.DTO.PB_ProductionOrderDetailData> GetTheDataOrderDetailInput(string OrderDetailQrCode)
        {
            //解析任务单明细二维码
            string[] usermodel = OrderDetailQrCode.Split(',');
            string Id = usermodel[1].ToString();
            string sqlMain = @" delete from PB_JobBookingQrCode where OrderDetailId='" + Id + "' and ParentId is null ";
            await ExecuteSqlAsync(sqlMain);
            DataTable dt = await Db.GetDataTableWithSqlAsync("select a.*,b.`Code` as MaterialCode,b.`Name` as MaterialName,b.SimpleName as MaterialSimpleName,c.`Name` as MaterialTypeName,b.Spec as MaterialSpec,b.Price as MaterialPrice,b.QrCode as MaterialQrCode,d.`Name` as UnitGroupName,(a.Productionquantity-(SELECT IFNULL(SUM(Nums),0) FROM PB_JobBooking where ParentId=a.Id))  as WorkReportNum,e.IsRefurbishment from PB_ProductionOrderDetail as a left join PB_Material as b on a.MaterialId=b.Id left join PB_MaterialType as c on b.MaterialTypeId=c.Id left join Base_UnitGroup as d on b.UnitGroupId=d.Id left join PB_ProductionOrder as e on a.ParentId=e.Id where a.Id='" + Id + "'");
            Entity.DTO.PB_ProductionOrderDetailData qdata = new Entity.DTO.PB_ProductionOrderDetailData();
            if (dt.Rows.Count > 0)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    qdata.Id = dr["Id"].ToString();
                    qdata.ParentId = dr["ParentId"].ToString();
                    qdata.MaterialId = dr["MaterialId"].ToString();
                    qdata.ProcecureId = dr["ProcecureId"].ToString();
                    qdata.Nums = Convert.ToDouble(dr["Nums"]);
                    qdata.Remarks = dr["Remarks"].ToString();
                    qdata.StartDate = Convert.ToDateTime(dr["StartDate"]);
                    qdata.EndDate = Convert.ToDateTime(dr["EndDate"]);
                    qdata.CreateTime = Convert.ToDateTime(dr["CreateTime"]);
                    qdata.CreatorId = dr["CreatorId"].ToString();
                    qdata.Deleted = Convert.ToBoolean(dr["Deleted"]);
                    qdata.HasCheck = Convert.ToBoolean(dr["HasCheck"]);
                    qdata.QrCode = dr["QrCode"].ToString();
                    qdata.WorkshopId = dr["WorkshopId"].ToString();
                    qdata.StationId = dr["StationId"].ToString();
                    qdata.Finishedproduct = dr["Finishedproduct"].ToString();
                    qdata.Ofmaterial = dr["Ofmaterial"].ToString();
                    qdata.Holespacing = dr["Holespacing"].ToString();
                    qdata.Productionquantity = Convert.ToInt32(dr["Productionquantity"]);
                    qdata.CompleteNums = Convert.ToDouble(dr["CompleteNums"]);
                    qdata.MaterialCode = dr["MaterialCode"].ToString();
                    qdata.MaterialName = dr["MaterialName"].ToString();
                    qdata.MaterialSimpleName = dr["MaterialSimpleName"].ToString();
                    qdata.MaterialTypeName = dr["MaterialTypeName"].ToString();
                    qdata.MaterialSpec = dr["MaterialSpec"].ToString();
                    qdata.MaterialQrCode = dr["MaterialQrCode"].ToString();
                    qdata.UnitGroupName = dr["UnitGroupName"].ToString();
                    qdata.WorkReportNum = Convert.ToDouble(dr["WorkReportNum"]);
                    qdata.IsRefurbishment = Convert.ToInt32(dr["IsRefurbishment"]);
                }
                return qdata;
            }
            else
            {
                throw new BusException("物料不存在");
            }
        }

        /// <summary>
        /// 通过项目id 获取 任务单明细信息
        /// </summary>
        /// <param name="ProjectId"></param>
        /// <returns></returns>
    public  async  Task<PageResult<ProjectProductionOrderList>> GetProjectProductionOrderList(PageInput<ProSubvConditionDTO> input, string ProjectId)
        {
            if (ProjectId == "2")
            {
                Expression<Func<PB_ProductionOrderDetail, PB_ProductionOrder, PB_DesignList, PB_Project, PB_Material, PB_MaterialType, Base_UnitItems, ProjectProductionOrderList>> select = (a, b, c, d, e, j, h) => new ProjectProductionOrderList
                {
                    MaterName = e.Name,
                    ProductionOrderName = b.POName,
                    ProName = d.Name,
                    ProjectId = d.Id,
                    MaterCode = e.Code,
                    MaterSpec = e.Spec,
                    MaterId = e.Id,
                    MaterialTypeId = j.Id,
                    UnitItemName = h.Name,
                    Weight = e.Weight,
                    Ofmaterial = e.Ofmaterial,
                    IsRefurbishment = b.IsRefurbishment,
                    States = b.Status,
                    Soure = b.State,
                    Productionquantity=a.Productionquantity-a.CompleteNums,
                    ProId=b.Id,
                };
                select = select.BuildExtendSelectExpre();
                var q = from a in GetIQueryable().AsExpandable()
                        join b in Db.GetIQueryable<PB_ProductionOrder>() on a.ParentId equals b.Id into ab
                        from b in ab.DefaultIfEmpty()
                        join c in Db.GetIQueryable<PB_DesignList>() on b.DesignId equals c.Id into ac
                        from c in ac.DefaultIfEmpty()
                        join d in Db.GetIQueryable<PB_Project>() on c.ProjectId equals d.Id into cd
                        from d in cd.DefaultIfEmpty()
                        join e in Db.GetIQueryable<PB_Material>() on a.MaterialId equals e.Id into ae
                        from e in ae.DefaultIfEmpty()
                        join j in Db.GetIQueryable<PB_MaterialType>() on e.MaterialTypeId equals j.Id into ej
                        from j in ej.DefaultIfEmpty()
                        join h in Db.GetIQueryable<Base_UnitItems>() on e.storageId equals h.Id into eh
                        from h in eh.DefaultIfEmpty()
                        select @select.Invoke(a, b, c, d, e, j, h);
                if (!input.Search.OrderName.IsNullOrEmpty())
                {
                    q = q.Where(x => x.ProId == input.Search.OrderName);
                }
                if (!input.Search.MaterialTypeId.IsNullOrEmpty())
                {
                    List<string> liststr = new List<string>();
                    List<PB_MaterialType> listdata = await Db.GetIQueryable<PB_MaterialType>().ToListAsync();
                    var typelist = listdata.Where(x => x.Id == input.Search.MaterialTypeId).FirstOrDefault();
                    if (typelist != null)
                    {
                        var typelist2 = listdata.Where(x => x.ParentId == typelist.Id).ToList();
                        if (typelist2.Count > 0)
                        {

                            foreach (var item in typelist2)
                            {
                                liststr.Add(item.Id);
                                GetItem(item.Id, liststr, listdata);
                            }
                            q = q.Where(w => liststr.Contains(w.MaterialTypeId));
                        }
                        else
                        {
                            q = q.Where(w => w.MaterialTypeId == input.Search.MaterialTypeId);
                        }
                    }
                }
                if (!input.Search.Keyword.IsNullOrEmpty())
                {
                    q = q.Where(x => x.MaterName.Contains(input.Search.Keyword) || x.MaterCode.Contains(input.Search.Keyword));
                }
               
                q = q.Where(x => x.States == 1&&x.Soure==true);
                q = q.Where(x => x.Productionquantity > 0);
                var res = await q.GetPageResultAsync(input);
                return res;
            }

            if (!ProjectId.IsNullOrEmpty()) {
                Expression<Func<PB_ProductionOrderDetail, PB_ProductionOrder, PB_DesignList, PB_Project, PB_Material, PB_MaterialType, Base_UnitItems, ProjectProductionOrderList>> select = (a, b, c, d, e, j, h) => new ProjectProductionOrderList
                {
                    MaterName = e.Name,
                    ProductionOrderName = b.POName,
                    ProName = d.Name,
                    ProjectId = d.Id,
                    MaterCode = e.Code,
                    MaterSpec = e.Spec,
                    MaterId = e.Id,
                    MaterialTypeId = j.Id,
                    UnitItemName = h.Name,
                    Weight = e.Weight,
                    Ofmaterial = e.Ofmaterial,
                    IsRefurbishment = b.IsRefurbishment,
                    States = b.Status,
                    Productionquantity = a.Productionquantity - a.CompleteNums,
                    ProId=b.Id,
                };
                select = select.BuildExtendSelectExpre();
                var q = from a in GetIQueryable().AsExpandable()
                        join b in Db.GetIQueryable<PB_ProductionOrder>() on a.ParentId equals b.Id into ab
                        from b in ab.DefaultIfEmpty()
                        join c in Db.GetIQueryable<PB_DesignList>() on b.DesignId equals c.Id into ac
                        from c in ac.DefaultIfEmpty()
                        join d in Db.GetIQueryable<PB_Project>() on c.ProjectId equals d.Id into cd
                        from d in cd.DefaultIfEmpty()
                        join e in Db.GetIQueryable<PB_Material>() on a.MaterialId equals e.Id into ae
                        from e in ae.DefaultIfEmpty()
                        join j in Db.GetIQueryable<PB_MaterialType>() on e.MaterialTypeId equals j.Id into ej
                        from j in ej.DefaultIfEmpty()
                        join h in Db.GetIQueryable<Base_UnitItems>() on e.storageId equals h.Id into eh
                        from h in eh.DefaultIfEmpty()
                        select @select.Invoke(a, b, c, d, e, j, h);
                if (!input.Search.OrderName.IsNullOrEmpty())
                {
                    q = q.Where(x => x.ProId == input.Search.OrderName);
                }
                if (!input.Search.MaterialTypeId.IsNullOrEmpty())
                {
                    List<string> liststr = new List<string>();
                    List<PB_MaterialType> listdata = await Db.GetIQueryable<PB_MaterialType>().ToListAsync();
                    var typelist = listdata.Where(x => x.Id == input.Search.MaterialTypeId).FirstOrDefault();
                    if (typelist != null)
                    {
                        var typelist2 = listdata.Where(x => x.ParentId == typelist.Id).ToList();
                        if (typelist2.Count > 0)
                        {

                            foreach (var item in typelist2)
                            {
                                liststr.Add(item.Id);
                                GetItem(item.Id, liststr, listdata);
                            }
                            q = q.Where(w => liststr.Contains(w.MaterialTypeId));
                        }
                        else
                        {
                            q = q.Where(w => w.MaterialTypeId == input.Search.MaterialTypeId);
                        }
                    }
                }
                if (!input.Search.Keyword.IsNullOrEmpty())
                {
                    q = q.Where(x => x.MaterName.Contains(input.Search.Keyword) || x.MaterCode.Contains(input.Search.Keyword));
                }
                if (!ProjectId.IsNullOrEmpty())
                {
                    q = q.Where(m => m.ProjectId == ProjectId);
                }
                q = q.Where(x => x.States ==1);
                q = q.Where(x=>x.Productionquantity>0);
                var res = await q.GetPageResultAsync(input);
                return res;
            }
         
            else {
                Expression<Func<PB_ProductionOrderDetail, PB_ProductionOrder, PB_Material, PB_MaterialType, Base_UnitItems, ProjectProductionOrderList>> select = (a, b, c, d, e) => new ProjectProductionOrderList
                {
                    MaterName = c.Name,
                    ProductionOrderName = b.POName,
                    MaterCode = c.Code,
                    MaterSpec = c.Spec,
                    MaterId = c.Id,
                    MaterialTypeId = d.Id,
                    UnitItemName = e.Name,
                    Weight = c.Weight,
                    Ofmaterial = a.Ofmaterial,
                    IsRefurbishment = b.IsRefurbishment,
                    States = b.Status,
                    Soure = b.State,
                    Productionquantity = a.Productionquantity - a.CompleteNums,
                    ProId=b.Id,
                };
                select = select.BuildExtendSelectExpre();
                var q = from a in GetIQueryable().AsExpandable()
                        join b in Db.GetIQueryable<PB_ProductionOrder>() on a.ParentId equals b.Id into ab
                        from b in ab.DefaultIfEmpty()
                        join c in Db.GetIQueryable<PB_Material>() on a.MaterialId equals c.Id into ac
                        from c in ac.DefaultIfEmpty()
                        join d in Db.GetIQueryable<PB_MaterialType>() on c.MaterialTypeId equals d.Id into cd
                        from d in cd.DefaultIfEmpty()
                        join e in Db.GetIQueryable<Base_UnitItems>() on c.storageId equals e.Id into ce
                        from e in ce.DefaultIfEmpty()
                        select @select.Invoke(a, b, c, d, e);
                if (!input.Search.OrderName.IsNullOrEmpty())
                {
                    q = q.Where(x => x.ProId == input.Search.OrderName);
                }
                if (!input.Search.MaterialTypeId.IsNullOrEmpty())
                {
                    List<string> liststr = new List<string>();
                    List<PB_MaterialType> listdata = await Db.GetIQueryable<PB_MaterialType>().ToListAsync();
                    var typelist = listdata.Where(x => x.Id == input.Search.MaterialTypeId).FirstOrDefault();
                    if (typelist != null)
                    {
                        var typelist2 = listdata.Where(x => x.ParentId == typelist.Id).ToList();
                        if (typelist2.Count > 0)
                        {

                            foreach (var item in typelist2)
                            {
                                liststr.Add(item.Id);
                                GetItem(item.Id, liststr, listdata);
                            }
                            q = q.Where(w => liststr.Contains(w.MaterialTypeId));
                        }
                        else
                        {
                            q = q.Where(w => w.MaterialTypeId == input.Search.MaterialTypeId);
                        }
                    }
                }
                if (!input.Search.Keyword.IsNullOrEmpty())
                {
                    q = q.Where(x => x.MaterName.Contains(input.Search.Keyword) || x.MaterCode.Contains(input.Search.Keyword));
                }
                q = q.Where(x => x.States == 1 && x.Soure == false);
                q = q.Where(x => x.Productionquantity > 0);
                var res = await q.GetPageResultAsync(input);
                return res;
            }
           

      
        }
        private List<string> GetItem(string Parentid, List<string> liststr, List<PB_MaterialType> listdata)
        {
            var itemlist = listdata.Where(x => x.ParentId == Parentid).ToList();
            foreach (var item in itemlist)
            {
                liststr.Add(item.Id);
                GetItem(item.Id, liststr, listdata);
            }
            return liststr;
        }
        public Task<List<Entity.DTO.PB_ProductionOrderDetailDTO>> GetDataListAsyncs(string ParentId)
        {
            throw new NotImplementedException();
        }


        #endregion

        #region 私有成员

        #endregion
    }
}